package com.ctyun.xstore.vod.video;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import com.ctyun.xstore.vod.AbstractVODClient;
import com.ctyun.xstore.vod.ConcurrentPartUploader;
import com.ctyun.xstore.vod.video.model.AuditVideoRequest;
import com.ctyun.xstore.vod.video.model.AuditVideoResponse;
import com.ctyun.xstore.vod.video.model.CreateVideoCompleteRequest;
import com.ctyun.xstore.vod.video.model.CreateVideoCompleteResponse;
import com.ctyun.xstore.vod.video.model.CreateVideoCoverRequest;
import com.ctyun.xstore.vod.video.model.CreateVideoCoverResponse;
import com.ctyun.xstore.vod.video.model.CreateVideoRequest;
import com.ctyun.xstore.vod.video.model.CreateVideoResponse;
import com.ctyun.xstore.vod.video.model.DeleteVideoRequest;
import com.ctyun.xstore.vod.video.model.DeleteVideoResponse;
import com.ctyun.xstore.vod.video.model.GetVideoFileInfoRequest;
import com.ctyun.xstore.vod.video.model.GetVideoFileInfoResponse;
import com.ctyun.xstore.vod.video.model.GetVideoFilesRequest;
import com.ctyun.xstore.vod.video.model.GetVideoFilesResponse;
import com.ctyun.xstore.vod.video.model.GetVideoRequest;
import com.ctyun.xstore.vod.video.model.GetVideoResponse;
import com.ctyun.xstore.vod.video.model.ModifyVideoRequest;
import com.ctyun.xstore.vod.video.model.ModifyVideoResponse;
import com.ctyun.xstore.vod.video.model.SearchVideoRequest;
import com.ctyun.xstore.vod.video.model.SearchVideoResponse;
import com.ctyun.xstore.vod.video.model.SignVideoFileRequest;
import com.ctyun.xstore.vod.video.model.SignVideoFileResponse;
import com.ctyun.xstore.vod.video.model.UploadVideoCoverRequest;
import com.ctyun.xstore.vod.video.model.UploadVideoCoverResponse;

public class VideoClient extends AbstractVODClient {

	private static final int CONVERT_UNIT = 1024 * 1024;

	private static final int VIDEO_COVER_MAX_ALLOWED_SIZE = 5;

	private static final int PICTURE_TYPE_INFO_BYTE = 4;

	private static final int HEX_BIT_SHIFT = 4;

	public VideoClient(String accessKey, String secretKey) {
		super(accessKey, secretKey);
	}

	public VideoClient(String host, String accessKey, String secretKey) {
		super(host, accessKey, secretKey);
	}

	/**
	 * file 初始化分片上传接口
	 * 
	 * @param request
	 * 
	 * @return
	 * 
	 * @throws IOException
	 */
	public CreateVideoResponse createVideo(CreateVideoRequest request) throws IOException {
		return this.execute(request, CreateVideoResponse.class);
	}

	/**
	 * 完成合并分片接口
	 * 
	 * @param request
	 * 
	 * @return
	 * 
	 * @throws IOException
	 */
	public CreateVideoCompleteResponse createVideoComplete(CreateVideoCompleteRequest request) throws IOException {
		return this.execute(request, CreateVideoCompleteResponse.class);
	}

	/**
	 * 删除视频接口
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public DeleteVideoResponse deleteVideo(DeleteVideoRequest request) throws IOException {
		return this.execute(request, DeleteVideoResponse.class);
	}

	/**
	 * 修改视频接口
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public ModifyVideoResponse modifyVideo(ModifyVideoRequest request) throws IOException {
		return this.execute(request, ModifyVideoResponse.class);
	}

	/**
	 * 人工审核视频接口
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public AuditVideoResponse auditVideo(AuditVideoRequest request) throws IOException {
		return this.execute(request, AuditVideoResponse.class);
	}

	/**
	 * 搜索视频接口
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public SearchVideoResponse searchVideo(SearchVideoRequest request) throws IOException {
		return this.execute(request, SearchVideoResponse.class);
	}

	/**
	 * 获取视频信息接口
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public GetVideoResponse getVideo(GetVideoRequest request) throws IOException {
		return this.execute(request, GetVideoResponse.class);
	}

	/**
	 * 取得源视频、转码视频文件信息接口
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public GetVideoFilesResponse getVideoFiles(GetVideoFilesRequest request) throws IOException {
		return this.execute(request, GetVideoFilesResponse.class);
	}

	/**
	 * 取得视频文件信息接口
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public GetVideoFileInfoResponse getVideoFileInfo(GetVideoFileInfoRequest request) throws IOException {
		return this.execute(request, GetVideoFileInfoResponse.class);
	}

	/**
	 * 对视频文件进行签名接口
	 * 
	 * @throws IOException
	 */
	public SignVideoFileResponse signVideoFile(SignVideoFileRequest request) throws IOException {
		return this.execute(request, SignVideoFileResponse.class);
	}

	/**
	 * 获取上传视频封面图片的预签名地址
	 */
	public CreateVideoCoverResponse createVideoCover(CreateVideoCoverRequest request) throws IOException {
		return this.execute(request, CreateVideoCoverResponse.class);
	}

	/**
	 * 上传视频封面图片
	 *
	 * @param presignedUrl
	 *            视频封面图片上传的预签名url
	 * @param filePath
	 *            视频封面图片文件本地路径
	 * @return
	 * @throws IOException
	 * @throws java.net.MalformedURLException
	 *             presignedUrl不符合规范
	 * @throws Exception
	 *             其他异常
	 */
	public void uploadVideoCover(String presignedUrl, String filePath) throws IOException {
		if (!isLegalPicture(filePath)) {
			throw new IllegalArgumentException("传入的视频封面图片不是JPG/PNG格式或者大小超过5M，请检查");
		}
		ConcurrentPartUploader s3UrlUploader = new ConcurrentPartUploader();
		s3UrlUploader.upload(presignedUrl, new File(filePath));
	}

	/**
	 * 完成视频封面图片上传
	 *
	 * @param
	 * @return UploadVideoCoverResponse, 完成视频封面图片上传的返回类，只包含code和message
	 * @throws IOException
	 *             可能抛出IO异常
	 */
	public UploadVideoCoverResponse completeVideoCover(UploadVideoCoverRequest request) throws IOException {
		return this.execute(request, UploadVideoCoverResponse.class);
	}

	/**
	 * 判断视频封面图片是否为jpg/png格式，以及大小是否超过5M
	 *
	 * @param filePath
	 *            文件路径
	 * @return boolean 文件是否符合要求
	 */
	private boolean isLegalPicture(String filePath) {
		byte[] b = new byte[PICTURE_TYPE_INFO_BYTE];
		try (FileInputStream fis = new FileInputStream(filePath)) {
			fis.read(b, 0, b.length);
			String type = byteArrayToHexStr(b);
			if (!type.contains("89504E47") && !type.contains("FFD8FF")) {
				return false;
			}
			if ((fis.available() + PICTURE_TYPE_INFO_BYTE) / CONVERT_UNIT > VIDEO_COVER_MAX_ALLOWED_SIZE) {
				return false;
			}
		} catch (IOException e) {
			return false;
		}
		return true;
	}

	/**
	 * byte数组转十六进制String的方法
	 *
	 * @param byteArray
	 * @return String
	 */
	private String byteArrayToHexStr(byte[] byteArray) {
		if (byteArray == null) {
			return null;
		}
		char[] hexArray = "0123456789ABCDEF".toCharArray();
		char[] hexChars = new char[byteArray.length * 2];
		for (int j = 0; j < byteArray.length; j++) {
			int v = byteArray[j] & 0xFF;
			hexChars[j * 2] = hexArray[v >>> HEX_BIT_SHIFT];
			hexChars[j * 2 + 1] = hexArray[v & 0x0F];
		}
		return new String(hexChars);
	}
}
